package com.iussoft.receiveData.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.apache.api.api.ApiService;
import com.apache.api.vo.ParamsVo;
import com.apache.api.vo.ResultEntity;
import com.apache.cache.util.Validator;
import com.apache.exception.BusinessException;
import com.apache.exception.ServiceException;
import com.apache.tools.*;
import com.iussoft.dxp.plugins.DefaultExcelExtend;
import com.iussoft.receiveData.interceptor.SuperInterceptor;
import com.iussoft.receiveData.manager.ReceiveManager;
import com.iussoft.receiveData.schedul.ScheduledDynamicTask;
import com.iussoft.receiveData.schedul.SendService;
import com.iussoft.tools.*;
import com.netflix.appinfo.ApplicationInfoManager;
import com.netflix.appinfo.EurekaInstanceConfig;
import com.netflix.appinfo.InstanceInfo;
import com.netflix.discovery.DiscoveryManager;
import com.netflix.discovery.EurekaClientConfig;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.*;
import java.util.Map.Entry;
import java.util.function.Function;
import java.util.stream.Collectors;

import static java.util.Map.*;

/**
 * description：统一数据接收接口
 *
 * @author dyh 创建时间：2018年06月29日
 */
@Controller
@RequestMapping("/receive/")
public class SearchController {

    @Autowired
    private ApiService receiveService;
    @Autowired
    protected ReceiveManager receiveManager;
    @Autowired
    @Qualifier("scheduledDynamicTask")
    private ScheduledDynamicTask dynamicTask;

    /**
     * 统一数据接收接口
     * https://XXXX/contextPath/data/{interfaceCode}/{sysPass}
     */
    @RequestMapping(value="/data/{interfaceCode}/",method = {RequestMethod.POST,RequestMethod.GET})
    public void searchData(HttpServletRequest request, HttpServletResponse response, @PathVariable("interfaceCode") String interfaceCode){
        sendMessage(request,response,interfaceCode,"");
    }

    /**
     * 统一数据接收接口
     * https://XXXX/contextPath/data/{interfaceCode}/{sysPass}
     */
    @RequestMapping(value="/data/{interfaceCode}/{sysPass}",method = {RequestMethod.POST,RequestMethod.GET})
    public void searchData(HttpServletRequest request, HttpServletResponse response, @PathVariable("sysPass") String sysPass, @PathVariable("interfaceCode") String interfaceCode){
        sendMessage(request,response,interfaceCode,sysPass);
    }

    /**
     * 内部统一数据接收接口
     * https://XXXX/contextPath/data/inner/{interfaceCode}
     */
    @RequestMapping(value="/data/inner/{interfaceCode}",method = RequestMethod.POST)
    public void searchInnerData(HttpServletRequest request, HttpServletResponse response, @PathVariable("interfaceCode") String interfaceCode){
        sendMessage(request,response,interfaceCode,"");
    }

    /**
     * 文件方式统一数据接收接口
     * https://XXXX/contextPath/file/{fileName}/{interfaceCode}
     */
    @RequestMapping(value="/file/data/{interfaceCode}",method = {RequestMethod.POST,RequestMethod.GET})
    //@ResponseBody
    public void uploadFileData(HttpServletRequest request, HttpServletResponse response, @PathVariable("interfaceCode") String interfaceCode) throws IOException {
        long startTime = System.currentTimeMillis();
        String traceId = SuperInterceptor.getTraceId(request);
        if(StrUtil.isNull(traceId)){
            traceId = UUIDUtil.getPrimaryKey();
            request.setAttribute("traceId",traceId);
        }
        String userIp = SuperInterceptor.getRequestIp(request);
        JSONObject obj = receiveManager.getInterfaceInfoForCode(interfaceCode);
        Map<String,Object> data = new HashMap();
        RequestMessage reqMsg = new RequestMessage();
        reqMsg.setTimestamp(startTime);
        reqMsg.setContent(obj);
        reqMsg.setRequestCode(interfaceCode);
        JSONObject json = new JSONObject();
        json.put("sendTime", System.currentTimeMillis());
        json.put("interfaceCode", obj.get("fromInterfaceCode"));
        json.put("infterfaceId", obj.get("fromServerId"));
        json.put("sysEname", obj.get("sysEname"));
        json.put("infterfacePwd", "");
        json.put("traceId", traceId);
        json.put("requestUseIp", userIp);
        json.put("requestCode", interfaceCode);
        json.put("dataType", "resp");
        String sourceMsge = null;
        String inputFileName =request.getParameter("inputFileName");
        Map<String,String> urlMap = getRequestParamMap(request,obj.getString("fromServerId"));
        urlMap.remove("inputFileName");
        urlMap.remove("fileName");
        Map<String,String> headMap = getRequestHead(request);
        String resultStr = null;
        boolean ifFTP = false;
        if(obj.containsKey("interfaceProtocol") && "ftp".equalsIgnoreCase(obj.getString("interfaceProtocol"))) {
            ifFTP = true;
        }
        try {
            if (request instanceof MultipartHttpServletRequest) {
                MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
                MultipartFile file = multipartRequest.getFile(inputFileName);
                reqMsg.setSourceMsg(file.getOriginalFilename()+"文件传输");
                json.put("sourceFile", file.getOriginalFilename());
                if (ifFTP) {
                    resultStr = receiveManager.sendFtp(obj, file.getInputStream(), file.getOriginalFilename(), urlMap);
                } else {
                    resultStr = receiveManager.sendHttp(obj.getString("interfaceUri"), file, null, inputFileName, "", null, urlMap);
                }
                sourceMsge = "{\"fileName\":\""+file.getOriginalFilename()+"\",\"fileSize\":\""+getFileSize(file.getSize())+"\"}";
            } else {
                String fileName = request.getParameter("fileName");
                reqMsg.setSourceMsg(fileName+"文件传输");
                json.put("sourceFile", fileName);
                MAPIHttpServletRequestWrapper req = new MAPIHttpServletRequestWrapper(request);
                if (ifFTP) {
                    resultStr = receiveManager.sendFtp(obj, req.getInputStream(), fileName, urlMap);
                } else {
                    resultStr = receiveManager.sendHttp(obj.getString("interfaceUri"), null, req.getInputStream(), inputFileName, fileName, null, urlMap);
                }
                sourceMsge = "{\"fileName\":\""+fileName+"\",\"fileSize\":\""+req.fileSize()+"\"}";
            }
        } catch (BusinessException e){
            LoggerUtil.warnSource("exception = {}; infoType = exception; traceId = {}; interfaceCode = {}; requestTime = {}; errorMessage={}; requestIp = {}; exeSys = receive; level = {}",e.getClass().getSimpleName(), traceId,obj.getString("fromInterfaceCode"),DateUtils.Now.fmt_yyyyMMdd_HHmmss(), e.getMessage(),userIp,"ERROR");
            data.put("errorCode", UnityErrorCode.UNKNOWN_ABNORMAL.getValue());
            data.put("errorMessage", e.getMessage());
        }
        if(StrUtil.isNotNull(sourceMsge)) {
            json.put("sourceMsg", sourceMsge);
            dynamicTask.submit(new SendService(json));
        }
        if(StrUtil.isNotNull(resultStr)) {
            data.put("errorCode", UnityErrorCode.SUCCESSFUL.getValue());
            data.put("errorMessage", UnityErrorCode.SUCCESSFUL.getDesc());
            data.put("entity", resultStr);
            request.setAttribute("RequestMessage", reqMsg);
        }
        request.setAttribute("responseMessage",data);
    }

    @RequestMapping(value = {"/import/{interfaceCode}"},method = {RequestMethod.POST})
    @ResponseBody
    public Object importExcel(HttpServletRequest request, HttpServletResponse response, @PathVariable("interfaceCode") String interfaceCode) throws IOException {
        Map<String,Object> data = new HashMap();
        MultipartFile file = null;
        if(request instanceof MultipartHttpServletRequest){
            MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
            file = multipartRequest.getFile("upfile");
        }
        if(file== null || file.isEmpty()){
            data.put("errorCode", UnityErrorCode.UNKNOWN_ABNORMAL.getValue());
            data.put("errorMessage", "请上传需要导入的*.xlsx文件");
            return data;
        }
        String comparisonRelation = request.getHeader("execl_title");
        Map<String,String> param = new HashMap();
        param.put("interfaceCode",interfaceCode);
        List<DataMap> list = receiveManager.select("dxInterfaceReg",param);
        if(StrUtil.isEmpty(list) || list.size()==0){
            data.put("errorCode", UnityErrorCode.UNKNOWN_ABNORMAL.getValue());
            data.put("errorMessage", "请求地址不正确");
            return data;
        }
        DataMap<String> interfaceInfo = list.get(0);
        if("1".equals(interfaceInfo.get("ifTest"))){
            data.put("errorCode", UnityErrorCode.SUCCESSFUL.getValue());
            data.put("errorMessage", UnityErrorCode.SUCCESSFUL.getDesc());
            data.put("entity", interfaceInfo.get("dataTest"));
            return data;
        }
        String infoCode = interfaceInfo.get("signConfPlug");
        Enumeration<String> parameterNames = request.getParameterNames();
        JSONObject defaultColumn = new JSONObject();
        while(parameterNames.hasMoreElements()){//遍历该控件/对象
            String name=String.valueOf(parameterNames.nextElement());//获得第 i 个控件/对象的name属性值，element是pNames对象的name属性值，
            String value=request.getParameter(name);//根据name属性值获取该控件的value值，与前端类似。
            defaultColumn.put(name, value);
        }

        InputStream in = null;
        try {
            List<Map<String,String>> listob = null;
            in = file.getInputStream();
            String fileName = file.getOriginalFilename();
            Object obj = null;
            if(StrUtil.isNotNull(infoCode)){//获取导入插件
                obj = SpringContextLoader.getBean(infoCode);
            }
            int totalRows = 0;
            String errorMessage = "";
            if(StrUtil.isNull(infoCode) || obj == null){//为空时走默认导入插件
                if(StrUtil.isNull(comparisonRelation)) {
                    data.put("errorCode", UnityErrorCode.UNKNOWN_ABNORMAL.getValue());
                    data.put("errorMessage", "字段映射关系不能为空！");
                    return data;
                }
                comparisonRelation = URLDecoder.decode(comparisonRelation, "UTF-8");
                JSONObject titleMap = JSONObject.parseObject(comparisonRelation);//key为excel中定义的title名字，value为接口报文字段名
                DefaultExcelExtend importExcel = new DefaultExcelExtend();
                importExcel.setTitles((Map)titleMap);
                listob = importExcel.customAnalyzeByExcel(in, fileName);
                totalRows = importExcel.getTotalRows();
                errorMessage = importExcel.getErrorMessage();
            } else {
                ImportExcelUtil importExcel = (ImportExcelUtil)obj;
                listob = importExcel.customAnalyzeByExcel(in, fileName);
                totalRows = importExcel.getTotalRows();
                errorMessage = importExcel.getErrorMessage();
            }
            //该处可调用service相应方法进行数据保存到数据库中，现只对数据输出
            if(!StrUtil.isEmpty(listob)){
                JSONObject json = new JSONObject();
                JSONObject dataJson = new JSONObject();
                dataJson.put("data",listob);
                json.put("sourceMsg", dataJson.toJSONString());
                json.put("sendTime", System.currentTimeMillis());
                json.put("interfaceCode", interfaceInfo.get("interfaceCode"));
                json.put("infterfaceId", interfaceInfo.get("infoId"));
                json.put("sysEname", interfaceInfo.get("sysEname"));
                json.put("infterfacePwd", "");
                json.put("traceId", SuperInterceptor.getRequestIp(request));
                json.put("requestUseIp", SuperInterceptor.getRequestIp(request));
                json.put("requestCode", interfaceCode);
                if(!defaultColumn.isEmpty()){//付默认值
                    json.put("defaultColumn", defaultColumn.toJSONString());
                }
                json.put("dataType", "resp");
                SendService sendService = new SendService(json);
                dynamicTask.submit(sendService);
                //kafkaSimpleSender.sendMsg(kafkaTopic, "0", json.toJSONString());
                data.put("errorCode", UnityErrorCode.SUCCESSFUL.getValue());
                data.put("errorMessage", "导入成功");
                JSONObject resultData = new JSONObject();
                resultData.put("total",totalRows);//总行数
                resultData.put("successNum",listob.size());//成功行数
                resultData.put("failureNum",totalRows-listob.size());//失败行数
                resultData.put("errorMessage",errorMessage);//失败行数
                data.put("entity", resultData);//返回结果
            } else {
                data.put("errorCode", UnityErrorCode.UNKNOWN_ABNORMAL.getValue());
                data.put("errorMessage", "文件解析总行数"+totalRows+" 成功解析0行，失败"+totalRows+"行;错误信息:"+errorMessage);
            }
        } catch (Exception e){
            data.put("errorCode", UnityErrorCode.UNKNOWN_ABNORMAL.getValue());
            data.put("errorMessage", "文件导入异常！");
        } finally {
            IOUtils.closeQuietly(in);
        }
        return data;
    }

    private void sendMessage(HttpServletRequest request, HttpServletResponse response,String interfaceCode,String sysPass){
        try {
            String traceId = SuperInterceptor.getTraceId(request);
            String ifBackup = request.getParameter("ifBackup");
            response.setContentType(request.getContentType());
            ParamsVo vo = new ParamsVo();
            RequestMessage reqMsg =(RequestMessage)request.getAttribute("RequestMessage");
            vo.setParams("traceId",traceId);
            vo.setParams("ifBackup",ifBackup);//是否开启备份
            vo.setParams("requestCode",interfaceCode);
            vo.setParams("requestUseIp",SuperInterceptor.getRequestIp(request));
            vo.setObj(reqMsg);
            Map<String,Object> data = new HashMap();
            ResultEntity entity = receiveService.doService(vo);
            if (null != entity.getEntity()) {
                data.put("errorCode", UnityErrorCode.SUCCESSFUL.getValue());
                data.put("errorMessage", UnityErrorCode.SUCCESSFUL.getDesc());
                data.put("entity", entity.getEntity());
            } else {
                data.put("errorCode", UnityErrorCode.UNKNOWN_ABNORMAL.getValue());
                data.put("errorMessage", entity.getMessage());
            }
            request.setAttribute("responseMessage",data);
        } catch (ServiceException e) {
            e.getStackTrace();
            request.setAttribute("errCode", e.getExpressionString());
            request.setAttribute("errMessage",e.getMessage());
        } catch (Exception e) {
            request.setAttribute("errCode", UnityErrorCode.UNKNOWN_ABNORMAL.getValue());
            request.setAttribute("errMessage", UnityErrorCode.UNKNOWN_ABNORMAL.getDesc());
            LoggerUtil.error("Exception异常：",e);
        }
    }

    /**
     * 下线本项目
     */
    @RequestMapping(value = "/offline", method = RequestMethod.GET)
    @ResponseBody
    public String offLine(HttpServletRequest request) {
        String sign = request.getParameter("sign");
        if("Constant.OFFLINE_KEY".equals(sign)){
            //EurekaClientConfig ecc = DiscoveryManager.getInstance().getEurekaClientConfig();
            //EurekaInstanceConfig eic = DiscoveryManager.getInstance().getEurekaInstanceConfig();
            //ApplicationInfoManager.getInstance().setInstanceStatus(InstanceInfo.InstanceStatus.DOWN);
           // DiscoveryManager.getInstance().initComponent(eic, ecc);
            DiscoveryManager.getInstance().shutdownComponent();
            return "下线成功";
        }
        return "签名不正确";
    }

    /**
     * 项目手动上线
     */
    @RequestMapping(value = "/online", method = RequestMethod.GET)
    @ResponseBody
    public String online(){
        if(!InstanceInfo.InstanceStatus.UP.equals(ApplicationInfoManager.getInstance().getInfo().getStatus())) {
            EurekaClientConfig ecc = DiscoveryManager.getInstance().getEurekaClientConfig();
            EurekaInstanceConfig eic = DiscoveryManager.getInstance().getEurekaInstanceConfig();
            ApplicationInfoManager.getInstance().setInstanceStatus(InstanceInfo.InstanceStatus.UP);
            DiscoveryManager.getInstance().initComponent(eic, ecc);
            return "上线成功";
        } else {
            return "服务处于发布状态不需上线操作";
        }
    }

    @Autowired
    private JedisPool jedisPool;
    /**
     * 设置定时任务
     */
    @ResponseBody
    @RequestMapping(value="/task/setTask",method = {RequestMethod.POST,RequestMethod.GET})
    public Object setTask(HttpServletRequest request) {
        Map<String, Object> data = new HashMap();
        data.put("code", "200");
        Jedis jedis = null;
        try {
            String reqMsg = IOUtils.toString(request.getInputStream(), "UTF-8");
            if(Validator.isNotNull(reqMsg)){
                jedis = jedisPool.getResource();
                jedis.select(10);
                JSONObject jsonObj = JSON.parseObject(reqMsg);
                String className = jsonObj.getString("className");
                Class<?> classType = Class.forName(className);
                Class[] parameterTypes = {String.class};//参数类型数组
                Object[] parameters={reqMsg}; //参数数组
                //根据参数类型获取相应的构造函数
                java.lang.reflect.Constructor constructor=classType.getConstructor(parameterTypes);
                Runnable call = (Runnable) constructor.newInstance(parameters);
                dynamicTask.startTask(jsonObj, call, jedis);
            }
            data.put("msg", "操作成功");
            data.put("taskIds", dynamicTask.getTaskIds());
        }catch(Exception e){
            e.printStackTrace();
            data.put("msg", "操作失败");
        } finally {
            if(null != jedis){
                jedis.close();
            }
        }
        return data;
    }

    /**
     * 停止定时任务
     */
    @ResponseBody
    @RequestMapping(value="/task/stop",method = {RequestMethod.POST,RequestMethod.GET})
    public Object stopTask(HttpServletRequest request) {
        Map<String, Object> data = new HashMap();
        data.put("code", "200");
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            jedis.select(10);
            String taskId = request.getParameter("taskId");
            if(Validator.isNotNull(taskId)) {
                boolean mark = dynamicTask.stopTask(taskId,jedis);
                data.put("msg", "操作成功;" + mark);
            }
            data.put("taskIds", dynamicTask.getTaskIds());
        }catch(Exception e){
            data.put("msg", "操作失败");
        }finally {
            if(null != jedis){
                jedis.close();
            }
        }
        return data;
    }

    /**
     * 查看定时任务
     */
    @ResponseBody
    @RequestMapping(value="/task/view",method = {RequestMethod.POST,RequestMethod.GET})
    public Object viewTask(HttpServletRequest request) {
        Map<String, Object> data = new HashMap();
        data.put("code", "200");
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            jedis.select(10);
            String taskId = request.getParameter("taskId");
            if(Validator.isNotNull(taskId)) {
               JSONObject task = dynamicTask.getTaskById(taskId,jedis);
                data.put("task",task);
            }else {
                data.put("tasks", dynamicTask.getTaskIds(jedis));
            }
        }catch(Exception e){
            data.put("msg", "操作失败");
        }finally {
            if(null != jedis){
                jedis.close();
            }
        }
        return data;
    }

    private Map<String,String> getRequestParamMap(HttpServletRequest request,String interfaceId) {
        Map<String,String> map = new HashMap();
        //得到枚举类型的参数名称，参数名称若有重复的只能得到第一个
        Enumeration enums = request.getParameterNames();
        while (enums.hasMoreElements()){
            String paramName = String.valueOf(enums.nextElement());
            if("traceId".equals(paramName)){
                continue;
            }
            String paramValue = request.getParameter(paramName);
            //形成键值对应的map
            map.put(paramName, paramValue);
        }
        if(StrUtil.isNotNull(interfaceId)) {
            Map<String,String> param = new HashMap();
            param.put("interfaceId",interfaceId);
            param.put("msgType","params");
            List<DataMap> data = receiveManager.select("dxMsgFormatSet",param);
            Map<String, Object> urlParams = data.stream().collect(Collectors.toMap(s->{
                return String.valueOf(s.get("paramEname"));
            }, Function.identity(),(s1, s2) -> s1));
            if (null != urlParams && !urlParams.isEmpty()) {
                for (String key : urlParams.keySet()) {
                    DataMap dmp = (DataMap)urlParams.get(key);
                    try {
                        String reqParam = StrUtil.doNull(map.get(key), String.valueOf(dmp.get("defValue")));
                        if (StrUtil.isNotNull(reqParam)) {
                            reqParam = URLEncoder.encode(StrUtil.doNull(map.get(key), String.valueOf(dmp.get("defValue"))), "UTF-8");
                        }
                        map.put(key, reqParam);
                    } catch (UnsupportedEncodingException e) {
                    }
                }
            }
        }
        return map;
    }

    private Map<String,String> getRequestHead(HttpServletRequest request){
        Map<String,String> map = new HashMap();
        Enumeration<String> headerNames = request.getHeaderNames();
        //获取获取的消息头名称，获取对应的值，并输出
        while(headerNames.hasMoreElements()){
            String nextElement = headerNames.nextElement();
            map.put(nextElement,request.getHeader(nextElement));
        }
        return map;
    }

    private String getFileSize(long leng) {
        String re = String.valueOf(leng);
        if (leng >= (1024 * 1024 * 1024)) {
            re = NumberUtils.divide(leng, (1024 * 1024 * 1024), 0) + "G";
        } else if (leng >= (1024 * 1024)) {
            re = NumberUtils.divide(leng, (1024 * 1024), 0) + "M";
        } else if (leng >= (1024)) {
            re = NumberUtils.divide(leng, (1024), 0) + "KB";
        } else {
            re = leng + "";
        }
        return re;
    }
}
